/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package graphic;

import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;

import javax.swing.JFrame;
import static java.lang.Math.*;


public class Board extends JFrame
{
   /**
	 * 
	 */
private static final long serialVersionUID = 1L;

public int xSize;
public int ySize;

public static int RADIUS=50;
public static int InsetsLeft=4;//got from Runtime
public static int InsetsRight=4;//got from Runtime
public static int InsetsTop=23;//got from Runtime
public static int InsetsBottom=4;//got from Runtime

public static double sqrt2=sqrt(2.0);

public Graphics graphics;

public Knoten[][] gitter;

public boolean targetFound=false;
public Knoten  targetFoundKnoten;

public ArrayList<Knoten> backPath = new ArrayList<Knoten>();

public static void main(String[] args) {
			     

	
}

   
   public Board(
		   int xSize, 
		   int ySize, 
		   int radius, int zeit, 
		   int startX, int startY,
		   int endX,   int endY
		   )
   {
	  
      super("Mein Diagramm zeit="+zeit);
      RADIUS=radius;
      this.xSize=xSize;
	  this.ySize=ySize;	  
	  gitter = new Knoten[ySize][xSize];
	  
	  int yOffset=4;
      int xOffset=-10;
      endX+=xOffset;
      endY+=yOffset;
      
	  initGitter(endX,endY);
	  setStart(startX, startY);
      
	  setTarget(endX, endY);
	  
	  setHindernis(startX+10, startY-6);
	  setHindernis(startX+10, startY-5);
	  setHindernis(startX+10, startY-4);
	  setHindernis(startX+10, startY-3);
	  setHindernis(startX+10, startY-2);
	  setHindernis(startX+10, startY-1);
	  setHindernis(startX+10, startY);
	  setHindernis(startX+10, startY+1);
	  setHindernis(startX+10, startY+2);
	  setHindernis(startX+10, startY+3);
	  setHindernis(startX+10, startY+4);
	  setHindernis(startX+10, startY+5);
	  setHindernis(startX+10, startY+6);
	  
	  
	  setHindernis(startX+12, startY-1);
	  setHindernis(startX+12, startY);
	  setHindernis(startX+12, startY+1);
	  setHindernis(startX+12, startY+2);
	  setHindernis(startX+12, startY+3);
	  setHindernis(startX+12, startY+4);
	  
	  /*
	  setHindernis(startX+20, startY+2);
	  setHindernis(startX+20, startY+3);
	  setHindernis(startX+20, startY+4);
	  setHindernis(startX+20, startY+5);
	  setHindernis(startX+20, startY+6);
	  setHindernis(startX+20, startY+7);
	  setHindernis(startX+20, startY+8);
	  setHindernis(startX+20, startY+9);
	  setHindernis(startX+20, startY+10);
	  */
	  
	  setHindernis(startX+23, startY-5);
	  setHindernis(startX+23, startY-4);
	  setHindernis(startX+23, startY-3);
	  setHindernis(startX+23, startY-2);
	  setHindernis(startX+23, startY);
	  setHindernis(startX+23, startY+1);
	  setHindernis(startX+23, startY+2);
	  setHindernis(startX+23, startY+3);
	  setHindernis(startX+23, startY+4);
	  
	  setHindernis(startX+23, startY+6);
	  setHindernis(startX+23, startY+7);
	  setHindernis(startX+23, startY+8);
	  setHindernis(startX+23, startY+9);
	  
	  
	  setHindernis(startX+26, startY+2);
	  setHindernis(startX+26, startY+3);
	  setHindernis(startX+26, startY+4);
	  setHindernis(startX+26, startY+5);
	  setHindernis(startX+26, startY+6);
	  setHindernis(startX+26, startY+7);
	  setHindernis(startX+26, startY+8);
	  setHindernis(startX+26, startY+9);
	  setHindernis(startX+26, startY+10);
	  setHindernis(startX+26, startY+11);
	  
	  calculateGitter(zeit, endY, endX);	  
	  
	  
	  
      addWindowListener
      (
         new WindowAdapter() 
         {
            public void windowClosing(WindowEvent event)
            {
               System.exit(0);
            }
         }
         
      );
      
      setBackground(Color.white);
      setSize((xSize)*RADIUS+InsetsLeft+InsetsRight,(ySize)*RADIUS+InsetsTop+InsetsBottom);      
      setVisible(true);    
      
   }
   
   public void setTarget(int endX, int endY) {
	   
	      int yOffset=0;
	      int xOffset=0;
	      setEnd(endX-1+xOffset, endY+yOffset);
		  setEnd(endX+xOffset, endY+yOffset);
		  setEnd(endX+1+xOffset, endY+yOffset);
		  
		  setEnd(endX+xOffset, endY-1+yOffset);	  
		  setEnd(endX+xOffset, endY+1+yOffset);
		  
		  setEnd(endX-1+xOffset, endY-3+yOffset);
		  setEnd(endX-1+xOffset, endY-1+yOffset);	  
		  setEnd(endX-1+xOffset, endY+1+yOffset);
		  setEnd(endX+1+xOffset, endY-1+yOffset);	  
		  setEnd(endX+1+xOffset, endY+1+yOffset);
   }
   
   public void setStart(int xStart, int yStart) {
	   gitter[yStart][xStart].status=Knoten.START_COL;	 
	   gitter[yStart][xStart].fuellungsGrad=Knoten.START_FUELLGR;
	   gitter[yStart][xStart].distanceFromStart=0;
	   
   }
   
   public void setEnd(int xEnd, int yEnd) {
	   gitter[yEnd][xEnd].status=Knoten.TARGET_COL;
	   gitter[yEnd][xEnd].fuellungsGrad=Knoten.TARGET_FUELLGR;	
   }
   
   public void setHindernis(int xHind, int yHind) {
	   gitter[ yHind][xHind]=new Knoten(Knoten.HIND_COL, Knoten.HIND_FUELLGR,
			   InsetsLeft+RADIUS*xHind,
			   InsetsTop+RADIUS*yHind,RADIUS
			   );
   }
   
   public void initGitter(int targetX, int targetY) {
	   
	   for (int zeilenIdx=0; zeilenIdx<xSize; zeilenIdx++) {
			  for (int spaltenIdx=0;spaltenIdx<ySize;spaltenIdx++) {
				  gitter[zeilenIdx][spaltenIdx]=new Knoten(Knoten.INIT_COL, Knoten.INIT_FUELLGR,
	                                          InsetsLeft+RADIUS*spaltenIdx,
	                                          InsetsTop+RADIUS*zeilenIdx,RADIUS);
				  gitter[zeilenIdx][spaltenIdx].luftlinie2Target=euklidianDistance(targetY,targetX,zeilenIdx, spaltenIdx);
				  gitter[zeilenIdx][spaltenIdx].gitterPosX=spaltenIdx;
				  gitter[zeilenIdx][spaltenIdx].gitterPosY=zeilenIdx;
			  }
		  }
	   
   }
   
   public static double sqr(double a) {
	   return a*a;
   }
   
   public ArrayList<Knoten> neighbourhood (int y, int x) {
       ArrayList<Knoten> neighbourhood=new ArrayList<Knoten>();
       
       for (int lx=x-1;lx<=x+1;lx++) {
    	   for (int ly=y-1;ly<=y+1;ly++) {
    		   if (  (lx!=x || ly!=y) 
    			  && lx>=0 && ly>=0 && lx<xSize && ly<ySize) {    			   
    			   gitter[ly][lx].proCameFrom=gitter[y][x];    			   
    			   neighbourhood.add(gitter[ly][lx]); 
    		   }
    	   }
       }
       
       return neighbourhood;
       
   }
   
   public static double euklidianDistance(int x1, int y1, int x2, int y2) {
	   return sqrt(sqr(x1-x2)+sqr(y1-y2));
   }
   
   public static double neighourhoodDistance(int x1, int y1, int x2, int y2) {
	   double retVal=-1;
	   if ((x1==x2) && (y1!=y2)) retVal=abs(y1-y2);
	   if ((x1!=x2) && (y1==y2)) retVal=abs(x1-x2);
	   if (abs(x1-x2)==1 && abs(y1-y2)==1) retVal=sqrt2;
	   if (retVal==-1) retVal=euklidianDistance(x1,y1,x2,y2);
	   return retVal;
   }
   
   public void calculateGitter(int zeit, int endY, int endX) {
	   
	   
	   for (int zeitIdx=0;zeitIdx<zeit && !targetFound;
	   zeitIdx++) {
		   
		   double minimum2Target=1000000.0;
		   Knoten mostPromisingKnoten=null;
		   for (int zeilenIdx=0; zeilenIdx<ySize; zeilenIdx++) {
			   for (int spaltenIdx=0;spaltenIdx<xSize;spaltenIdx++) {				  
				   Knoten currKnoten = gitter[zeilenIdx][spaltenIdx];
				   ArrayList<Knoten> neighbourhood = neighbourhood(zeilenIdx,spaltenIdx);				  
				   for (Knoten nb_knoten : neighbourhood) {
					   if (currKnoten.status==Knoten.START_COL || currKnoten.status==Knoten.KNOWN_COL)
						   	if (!(nb_knoten.status==Knoten.START_COL || nb_knoten.status==Knoten.HIND_COL)) {
						   		
						   		nb_knoten.nextStatus=Knoten.KNOWN_COL;
					            nb_knoten.nextFuellGrad=Knoten.KNOWN_FUELLGR;	
					            double distanceFromStart=currKnoten.distanceFromStart+
					            		Knoten.distance(currKnoten, nb_knoten);
					            if (distanceFromStart<nb_knoten.distanceFromStart) 
					            	nb_knoten.distanceFromStart=distanceFromStart;
					            if (nb_knoten.status!=Knoten.KNOWN_COL && nb_knoten.distanceFromStart+nb_knoten.luftlinie2Target<minimum2Target) {
					            	minimum2Target=nb_knoten.distanceFromStart+nb_knoten.luftlinie2Target;
					            	mostPromisingKnoten=nb_knoten;
					            	mostPromisingKnoten.cameFrom=gitter[zeilenIdx][spaltenIdx];
					            }
						   	}
				   }		  
			   }
		   }
	   
		   for (int zeilenIdx=0; zeilenIdx<ySize; zeilenIdx++) {
			  for (int spaltenIdx=0;spaltenIdx<xSize;spaltenIdx++) {
					  if (zeilenIdx==mostPromisingKnoten.gitterPosY && spaltenIdx==mostPromisingKnoten.gitterPosX) {						  
						  if (gitter[zeilenIdx][spaltenIdx].status==Knoten.TARGET_COL) {
				    		  targetFound=true;
				    		  targetFoundKnoten=gitter[zeilenIdx][spaltenIdx];
				    	  } else {
				    		  gitter[zeilenIdx][spaltenIdx].status=gitter[zeilenIdx][spaltenIdx].nextStatus;
				    		  gitter[zeilenIdx][spaltenIdx].fuellungsGrad=gitter[zeilenIdx][spaltenIdx].nextFuellGrad;
				    		  gitter[zeilenIdx][spaltenIdx].cameFrom=mostPromisingKnoten.cameFrom;				    		  				    		  
				    	  }
				      }
			  }
		  }
	   }
	   
   }
   
           
   public void paint(Graphics g)
   {
	   
	   if (targetFound) {
	   g.setColor(Color.red);
	   Knoten prevKnoten=targetFoundKnoten;
	   
	   	while (prevKnoten.cameFrom!=null) {
	   			Knoten pprevKnoten=prevKnoten.cameFrom;
	   			
	   			for (int yIdx=-2;yIdx<3;yIdx++) {
	   			g.drawLine( 
	   					RADIUS/2+pprevKnoten.posX, RADIUS/2+pprevKnoten.posY+yIdx,
	   					RADIUS/2+ prevKnoten.posX, RADIUS/2+ prevKnoten.posY+yIdx
	   					);
	   			}
	   			prevKnoten=pprevKnoten;
	   	}
	   }
	   
	    this.graphics=g;
        Graphics2D g2 = (Graphics2D)g;
                
        int anzSpalten=xSize;
        int anzZeilen=ySize;
        for (int zeileIdx=0;zeileIdx<anzZeilen;zeileIdx++) {
          for (int spalteIdx=0;spalteIdx<anzSpalten;spalteIdx++) {
        		gitter[zeileIdx][spalteIdx].draw(g,g2);
        		}
        } 
   }
   
   
}